package org.asiainfo.auth.service.impl;

import cloud.tianai.captcha.spring.autoconfiguration.ImageCaptchaProperties;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.asiainfo.auth.service.ISysLoginService;
import org.asiainfo.common.core.constant.UserConstants;
import org.asiainfo.common.core.exception.ServiceException;
import org.asiainfo.common.core.exception.user.UserException;
import org.asiainfo.common.core.utils.SpringUtils;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.redis.utils.RedisUtils;
import org.asiainfo.common.satoken.utils.LoginHelper;
import org.asiainfo.system.api.RemoteUserService;
import org.asiainfo.system.api.model.LoginUser;
import org.asiainfo.system.api.domain.vo.RemoteClientVo;
import org.springframework.stereotype.Service;

import static org.asiainfo.common.core.constant.CacheNames.CLIENT_KEY;
import static org.asiainfo.common.core.constant.CacheNames.REFRESH_TOKEN_KEY;

/**
 * 用户登录
 *
 * @author dotor-ww
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SysLoginServiceImpl implements ISysLoginService {

    private final ImageCaptchaProperties imageCaptchaProperties;

    @DubboReference
    private RemoteUserService remoteUserService;

    /**
     * 校验客户端
     *
     * @param clientVo  客户端
     * @param grantType 授权类型
     */
    @Override
    public void checkClientId(RemoteClientVo clientVo, String grantType) {
        if (ObjectUtil.isNull(clientVo) || !StringUtils.contains(clientVo.getGrantType(), grantType)) {
            log.info("客户端id: {} 认证类型：{} 异常!", clientVo.getClientId(), grantType);
            throw new ServiceException("auth.grant.type.error");
        } else if (!UserConstants.NORMAL.equals(clientVo.getStatus())) {
            throw new ServiceException("auth.grant.type.blocked");
        }
    }

    /**
     * 二次校验验证码
     *
     * @param id 验证码ID
     */
    @Override
    public void secondCheckCaptcha(String id) {
        // 判断验证码开关
        if (!getCaptchaEnabled()) {
            return;
        }
        if (StringUtils.isEmpty(id)) {
            throw new UserException("user.captcha.not.null");
        }
        //二次校验
        String secondPrefix = imageCaptchaProperties.getSecondary().getKeyPrefix();
        //验证码缓存Key
        String key = String.join(":", secondPrefix, id);
        if (!RedisUtils.hasKey(key)) {
            throw new UserException("user.captcha.error");
        }
        //清除二次校验验证码
        RedisUtils.deleteObject(key);
    }

    /**
     * 用户退出
     *
     * @param refreshToken 刷新令牌
     */
    @Override
    public void logout(String refreshToken) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        //判断当前请求是否存在用户
        if (ObjectUtil.isNull(loginUser)) {
            return;
        }
        if (StringUtils.isNotBlank(refreshToken)) {
            SaTempUtil.deleteToken(refreshToken);
        }
        //记录退出日志
        StpUtil.logout();
    }

    /**
     * 刷新token
     *
     * @param userId   用户ID
     * @param tenantId 租户ID
     * @param clientVo 客户端
     * @return token
     */
    @Override
    public String refreshToken(Long userId, Long tenantId, RemoteClientVo clientVo) {
        //清除之前的登录信息
        StpUtil.logout();
        SaLoginModel model = new SaLoginModel();
        model.setDevice(clientVo.getDeviceType());
        model.setTimeout(clientVo.getTimeout());
        model.setActiveTimeout(clientVo.getActiveTimeout());
        model.setExtra(CLIENT_KEY, clientVo.getClientId());
        model.setExtra(REFRESH_TOKEN_KEY, userId);
        LoginUser loginUser = remoteUserService.getUserInfo(userId, tenantId);
        loginUser.setClientKey(clientVo.getClientKey());
        loginUser.setDeviceType(clientVo.getDeviceType());
        LoginHelper.login(loginUser, model);
        return StpUtil.getTokenSession().getToken();
    }

    /**
     * 获取验证码开关状态
     *
     * @return 状态
     */
    private Boolean getCaptchaEnabled() {
        return Convert.toBool(SpringUtils.getProperty("security.captcha.enabled"), false);
    }
}
